package emulator.unittest.hardware.nmos6502;

import static org.junit.Assert.*;

import java.io.ByteArrayOutputStream;
import java.io.PrintStream;

import org.junit.Test;

import emulator.hardware.HwByte;
import emulator.hardware.HwWord;
import emulator.hardware.memory.SparseMemory;
import emulator.hardware.nmos6502.Cpu6502;

public class Cpu6502PrintOpcodeTest {

	@Test
	public void testLDX_Immediate() {
		checkPrintOpcode(new int[] { 0xA2, 0xFF }, "LDX #$FF");
	}

	@Test
	public void testSEI() {
		checkPrintOpcode(new int[] { 0x78 }, "SEI ");
	}

	@Test
	public void testTXS() {
		checkPrintOpcode(new int[] { 0x9A }, "TXS ");
	}

	@Test
	public void testCLD() {
		checkPrintOpcode(new int[] { 0xD8 }, "CLD ");
	}

	@Test
	public void testJSR() {
		checkPrintOpcode(new int[] { 0x20, 0x3F, 0xFD }, "JSR $FD3F");
	}

	@Test
	public void testLDA_AbsoluteX() {
		checkPrintOpcode(new int[] { 0xBD, 0xFE, 0xAF }, "LDA $AFFE,X");
	}

	@Test
	public void testSTA_ZeroPageX() {
		checkPrintOpcode(new int[] { 0x95, 0xFE }, "STA $FE,X");
		checkPrintOpcode(new int[] { 0x95, 0x00 }, "STA $00,X");
	}
	
	@Test
	public void testBNE() {
		checkPrintOpcode(new int[] { 0xD0, 0xF5 }, "BNE $0FF7");
	}

	@Test
	public void testSTA_ZeroPage() {
		checkPrintOpcode(new int[] { 0x85, 0xFE }, "STA $FE");
	}
	
	@Test
	public void testSTA_IndirectX() {
		checkPrintOpcode(new int[] { 0x81, 0xC1 }, "STA ($C1,X)");
	}
	
	@Test
	public void testSTA_IndirectY() {
		checkPrintOpcode(new int[] { 0x91, 0xC1 }, "STA ($C1),Y");
	}
	
	private void checkPrintOpcode(int[] sequence, String expected_result) {
		SparseMemory memory = new SparseMemory();
		for (int i = 0; i < sequence.length; i++)
			memory.write(0x1000+i, sequence[i]);
		Cpu6502 cpu = new Cpu6502();
		cpu.attach(memory, null);
		cpu.setPC(0x1000);
		cpu.setAccu(new HwByte(0x12));
		cpu.setX(new HwByte(0x3F));
		cpu.setY(new HwByte(0x9A));
		ByteArrayOutputStream out_buf = new ByteArrayOutputStream(); 
		cpu.printNextOpcode(new PrintStream(out_buf));
		String prefix = "";
		for (int i = 0; i < 3; i++)
			if (i < sequence.length)
				prefix += new HwByte(sequence[i]) + " ";
			else
				prefix += "   ";
		assertEquals(new HwWord(0x1000), cpu.getPC());
		assertEquals(prefix + " " + expected_result + "\r\n",
						out_buf.toString());
	}

}
